
#include "commmsg.h"
#include "cmdequipinfo.h"
#include "../mainctrl.h"
#include "../cmd/dataprepare.h"
#include "../partner/CUserPartner.h"
#include "../storage/CUserStorage.h"
#include "../storage/CStorageMgr.h"
#include "../matrix/CMatrixMgr.h"
#include "MsgStorage.pb.h"
#include "MsgEquipInfo.pb.h"

CT_REGISTER_ASYNCCMD(ID_MAIN_EQUIP_ROLE, CCmdEquipRole);
int CCmdEquipRole::Do(void* pData)
{
    CT_ASSERT(pData);

    //解析消息
    CCmdPBDoParam* pstParam = (CCmdPBDoParam*) pData;
    pstMainCtrl = (CMainCtrl*) pstParam->m_pMain;

    if (pstParam->m_pstMsgHead->msgid() != ID_MAIN_EQUIP_ROLE ||
        pstParam->m_pstMsgHead->msgtype() != CSMsgDef::EMT_REQUEST)
    {
        CT_ERROR(("Cmd Stat Err Cmd=%d CmdID=%d Tpye=%d",
            ID_MAIN_EQUIP_ROLE,
            pstParam->m_pstMsgHead->msgid(),
            pstParam->m_pstMsgHead->msgtype()));
        return Done(RET_SYS_ERROR);
    }

    stMsgHead = *(pstParam->m_pstMsgHead);
    stEnpHead = *(pstParam->m_pstEnpHead);
    int iRet = pstMainCtrl->DecodePBMsg(stReq, pstParam);
    if (iRet)
    {
        return AnsClients(iRet);
    }
    //消息解析结束

    _uiGid = stReq.gid();

    //检查登录
    iRet = pstMainCtrl->CheckLogin(_uiGid, stEnpHead);
    if (iRet != RET_OK)
    {
        return AnsClients(iRet);
    }

    LogicDo(RET_OK);
	return RET_OK;
}

int CCmdEquipRole::LogicDo(int iRet)
{
    if (iRet != 0)
    {
        return AnsClients(iRet);
    }

    PREPARE_PLAYER_BASE_INFO(this, stReq.gid());
    ASSERT_PLAYER_PREPARED(stReq.gid());

    PREPARE_PLAYER_DETAIL_INFO(this, stReq.gid());
    ASSERT_PLAYER_DETAIL_PREPARED(stReq.gid());

    int iIndex;
    iIndex = pstMainCtrl->m_stPlayerBaseInfoHash.HashFind(stReq.gid());
    if (iIndex < 0)
    {
        return AnsClients(RET_NO_USER);
    }
    CPlayerBaseInfo& stPlayerBaseInfo = pstMainCtrl->m_stPlayerBaseInfoHash[iIndex];

    if (stPlayerBaseInfo._ucIsInited != 1)
    {
        return AnsClients(ERROR_NOT_INITED);
    }

    iIndex = pstMainCtrl->m_stPlayerDetailInfoHash.HashFind(stReq.gid());
    if (iIndex < 0)
    {
        return AnsClients(RET_NO_USER);
    }
    CPlayerDetailInfo& stPlayerDetailInfo = pstMainCtrl->m_stPlayerDetailInfoHash[iIndex];

    iIndex = pstMainCtrl->m_stPlayerOnlineDataHash.HashFind(stReq.gid());
    if (iIndex < 0)
    {
        return AnsClients(RET_NO_USER);
    }
    CPlayerOnlineData& stPlayerOnlineData = pstMainCtrl->m_stPlayerOnlineDataHash[iIndex];

    //先判断,装备是否能穿上. (情况1: 穿背包中指定位置的装备. 情况2: 脱到背包的格子上是装备)
    iRet = PreCheck(stPlayerBaseInfo, stPlayerDetailInfo, stPlayerOnlineData);
    if (iRet)
    {
        return AnsClients(iRet);
    }

    short shRoleId = (short)(stReq.partner_id() & 0x7FFF);

    //如果身上有装备, 先将装备脱到_stRoleGrid中.
    iRet = TakeoffEquip(stPlayerBaseInfo, stPlayerDetailInfo, stPlayerOnlineData);
    if (iRet)
    {
        return AnsClients(iRet);
    }

    unsigned char ucEquipPos = (unsigned char)_stRoleGrid._stKey._usStorePos;

    //穿背包中格子里的装备.
    iRet = WareEquip(stPlayerBaseInfo, stPlayerDetailInfo, stPlayerOnlineData);
    if (iRet)
    {
        return AnsClients(iRet);
    }

    //将脱下来的装备,存放到背包中.
    iRet = PutEquipToBag(stPlayerDetailInfo, stPlayerOnlineData);
    if (iRet)
    {
        return AnsClients(iRet);
    }

    if (stReq.oper_type() == CCmdEquipRole::PARTNER_WEAR_EQUIP)
    {
        //触发任务
        pstMainCtrl->m_stTaskMgr.TriggerDoSomeOpt(stPlayerOnlineData._stUserTask, 103000 + ucEquipPos, 1);
    }

    pstMainCtrl->m_stStorageMgr.GetData(stPlayerOnlineData._stUserStorage, stPlayerDetailInfo._stUserStorage);
    pstMainCtrl->m_stEquipMgr.GetData(stPlayerOnlineData._stUserEquip, stPlayerDetailInfo._stUserEquip);

    stAns.set_gid(_uiGid);
    stAns.set_partner_id(shRoleId);
    pstMainCtrl->m_stStorageMgr.GetGridInfo (_uiGid, _stBagGrid, *stAns.mutable_bag_grid());  
    pstMainCtrl->m_stStorageMgr.GetGridInfo (_uiGid, _stRoleGrid, *stAns.mutable_role_grid());

	//内容同步到数据库
    CVarObjectKey stKey;
    stKey.m_chDataType = DT_PLAYER_BASE_INFO;
    stKey.m_u64ID = stPlayerBaseInfo._uiGID;
    pstMainCtrl->UpdateData(stKey, stPlayerBaseInfo, VOP_UPDATE);

    stKey.m_chDataType = DT_PLAYER_DETAIL_INFO;
    stKey.m_u64ID = stPlayerDetailInfo._uiGID;
    pstMainCtrl->UpdateData(stKey, stPlayerDetailInfo, VOP_UPDATE);

    //下发战斗力
    if (stReq.partner_id() == 0 || pstMainCtrl->m_stMatrixMgr.PartnerInMainMatrix(stPlayerDetailInfo, stReq.partner_id()))
    {
        pstMainCtrl->m_stMatrixMgr.SendMatrixFightingToFront(stPlayerBaseInfo, stPlayerDetailInfo, stPlayerOnlineData);
    }

	return AnsClients(RET_OK);
}

int CCmdEquipRole::GetEquipOnRole (CPlayerDetailInfo & stPlayerDetailInfo, short shRoleId, unsigned char ucEquipPos, unsigned int & uiNowEquip)
{
    int iRet;
    if (shRoleId != 0)
    {
        iRet = stPlayerDetailInfo._stUserPartner.GetEquip(shRoleId, uiNowEquip, ucEquipPos);
    }
    else
    {
        iRet = stPlayerDetailInfo._stPlayerEquip.GetEquip(uiNowEquip, ucEquipPos);
    }

    return iRet;
}

int CCmdEquipRole::PreCheck (CPlayerBaseInfo& stPlayerBaseInfo, CPlayerDetailInfo& stPlayerDetailInfo, CPlayerOnlineData& stPlayerOnlineData)
{
    unsigned char ucEquipOp = (unsigned char)(stReq.oper_type()& 0x7F);
    if ((ucEquipOp != CCmdEquipRole::PARTNER_WEAR_EQUIP)
        && (ucEquipOp != CCmdEquipRole::PARTNER_TAKEOFF_EQUIP))
    {
        return ERROR_EQUIP_OPER_UNSURPORT;
    }

    int iRet;
    short shToLevel = 0;
    char cRoleCareer;
    short shRoleID = (short)(stReq.partner_id() & 0x7FFF);
    if (0 == shRoleID)
    {
        shToLevel = stPlayerBaseInfo._shLevel;
        cRoleCareer = stPlayerBaseInfo._ucCareer;
    }
    else
    {
        int iIndex = stPlayerDetailInfo._stUserPartner.FindActData(shRoleID);
        if (iIndex < 0)
        {
            return ERROR_EQUIP_PARTNER_ACT;
        }

        const CPartnerActData& stPartner = stPlayerDetailInfo._stUserPartner.GetPartnerActData(iIndex);
        shToLevel = stPartner._shLevel;

        CPartnerCfgData stCfgData;
        iRet = pstMainCtrl->m_stPartnerMgr.GetPartnerCfg(shRoleID, stCfgData);
        CHECK_RETURN(iRet);
        cRoleCareer = stCfgData.GetCareer();
    }

    if (CCmdEquipRole::PARTNER_WEAR_EQUIP == ucEquipOp)
    {
        unsigned char ucEquipFromType = (unsigned char)(stReq.equip_from_pos_type() & 0x7F);
        if (STORAGE_TYPE_BAG != ucEquipFromType)
        {
            return ERROR_WEAR_NOTBAG_EQUIP;
        }

        iRet = pstMainCtrl->m_stStorageMgr.GetGridInfoByPos(stPlayerOnlineData._stUserStorage, true,
                                                             stReq.equip_from_pos(), _stBagGrid);
        CHECK_RETURN(iRet);
    }
    else
    {
        _stRoleGrid._stKey._usStorePos = stReq.equip_take_off_pos();

        //脱到背包的指定格子上
        unsigned char ucEquipToType = (unsigned char)(stReq.equip_to_pos_type() & 0x7F);
        if (STORAGE_TYPE_BAG == ucEquipToType)
        {
            iRet = pstMainCtrl->m_stStorageMgr.GetGridInfoByPos(stPlayerOnlineData._stUserStorage, true,
                                                                stReq.equip_to_pos(), _stBagGrid);
            CHECK_RETURN(iRet);

            if (_stBagGrid.IsEmpty())
            {
                _stBagGrid._stKey._usStorePos = stReq.equip_to_pos();
                return 0;
            }
        }
        else
        {
            //不指定格子,判断背包是否为空.
            if (stPlayerOnlineData._stUserStorage.BagIsFull())
            {
                return ERROR_STORAGE_BAG_IS_FULL;
            }

            return 0;
        }
    }

    if (_stBagGrid._stKey._ucItemType != ITEM_TYPE_EQUIP)
    {
        return ERROR_GRID_NOT_EQUIP;
    }

    //检验人物等级是否达到装备等级
    unsigned int uiEquipId = _stBagGrid._stKey._uiItemID;
    CEquipConfigData stConfigData;
    iRet = pstMainCtrl->m_stEquipMgr.GetConfigData(uiEquipId, stConfigData);
    CHECK_RETURN(iRet);

    CSingleEquip stEquip;
    iRet = pstMainCtrl->m_stEquipMgr.GetEquip(stPlayerOnlineData._stUserEquip, uiEquipId, stEquip);
    CHECK_RETURN(iRet);

    //判断是否符合装备穿戴的条件
    if (shToLevel < stConfigData._usUseLevel)
    {
        return ERROR_EQUIP_ROLE_LEVEL;
    }

    if (stConfigData._ucEquipPos == EQUIP_POS_WEAPON)
    {
        if (stConfigData._ucCareerType != cRoleCareer)
        {
            return ERROR_EQUIP_WEAPON_NOT_MATCH;
        }
    }

    //判断背包中物品穿戴的位置,跟操作的人身上的格子是否一致
    if (CCmdEquipRole::PARTNER_TAKEOFF_EQUIP == ucEquipOp)
    {
        if (stConfigData._ucEquipPos != stReq.equip_take_off_pos())
        {
            return ERROR_EQUIP_NOT_MATCH;
        }
    }

    _stRoleGrid._stKey._usStorePos = stConfigData._ucEquipPos;
    return 0;
}

int CCmdEquipRole::TakeoffEquip(CPlayerBaseInfo& stPlayerBaseInfo, CPlayerDetailInfo& stPlayerDetailInfo, CPlayerOnlineData& stPlayerOnlineData)
{
    int iRet = 0;
    unsigned int uiNowEquip = 0;
    short shRoleId = (short)(stReq.partner_id() & 0x7FFF);
    unsigned char ucEquipPos = _stRoleGrid._stKey._usStorePos; //穿脱位置

    iRet = GetEquipOnRole(stPlayerDetailInfo, shRoleId, ucEquipPos, uiNowEquip);
    CHECK_RETURN(iRet);

    if (0 == uiNowEquip)
    {
        return 0;
    }
    
    //在装备控制器中,  保存穿戴的伙伴信息
    iRet = pstMainCtrl->m_stEquipMgr.TakeOffEquip(stPlayerOnlineData._stUserEquip, uiNowEquip);
    CHECK_RETURN(iRet);

    //脱下身上已有的装备
    if (shRoleId != 0)
    {
        iRet = pstMainCtrl->m_stPartnerMgr.PartnerTakeOffEquip(shRoleId,
            stPlayerBaseInfo,stPlayerDetailInfo, stPlayerOnlineData, uiNowEquip,
            ucEquipPos);

    }
    else
    {
        iRet = pstMainCtrl->m_stRoleMgr.RoleTakeOffEquip(stPlayerBaseInfo, stPlayerDetailInfo,
            stPlayerOnlineData, uiNowEquip, ucEquipPos);
    }

    if (iRet)
    {
        CT_ERROR (("gid: %d, partner %d, equipid: %d", stPlayerBaseInfo._uiGID, shRoleId,uiNowEquip));
        return iRet;
    }

    //保存脱下的装备,以便加入到背包中
    _stRoleGrid._stKey._ucItemType = ITEM_TYPE_EQUIP;
    _stRoleGrid._stKey._uiItemID = uiNowEquip;
    _stRoleGrid._shCount = 1;

    return 0;
}

int CCmdEquipRole::WareEquip(CPlayerBaseInfo& stPlayerBaseInfo, CPlayerDetailInfo& stPlayerDetailInfo, CPlayerOnlineData& stPlayerOnlineData)
{
    int iRet = 0;

    //穿上背包中的装备
    short shRoleId = (short)(stReq.partner_id() & 0x7FFF);
    unsigned int uiEquipID = _stBagGrid._stKey._uiItemID;
    if (0 == uiEquipID)
    {
        return 0;
    }

    iRet = pstMainCtrl->m_stEquipMgr.WearEquip(stPlayerOnlineData._stUserEquip, uiEquipID, shRoleId);
    CHECK_RETURN(iRet);

    //在人物身上保存装备ID
    if (0 == shRoleId)
    {
        iRet = pstMainCtrl->m_stRoleMgr.RoleWearEquip(stPlayerBaseInfo, stPlayerDetailInfo,
                    stPlayerOnlineData, uiEquipID, _stRoleGrid._stKey._usStorePos);
        CHECK_RETURN(iRet);
    }
    else
    {
        iRet = pstMainCtrl->m_stPartnerMgr.PartnerWearEquip(stReq.partner_id(),
            stPlayerBaseInfo, stPlayerDetailInfo, stPlayerOnlineData,
            uiEquipID, _stRoleGrid._stKey._usStorePos);
        CHECK_RETURN(iRet);
    }

    CStorageGrid stGrid;
    iRet = pstMainCtrl->m_stStorageMgr.TakeOutGrid(stPlayerOnlineData._stUserStorage, _stBagGrid._stKey._usStorePos, stGrid);
    CHECK_RETURN(iRet);

    return 0;
}

int CCmdEquipRole::PutEquipToBag (CPlayerDetailInfo & stPlayerDetailInfo, CPlayerOnlineData & stPlayerOnlineData)
{
    if (0 == _stRoleGrid._stKey._uiItemID)
    {
        //返回给前台信息时使用,
        _stRoleGrid._shCount = 1;
        _stRoleGrid._stKey._ucItemType = ITEM_TYPE_EQUIP;
        _stRoleGrid._stKey._uiItemID = _stBagGrid._stKey._uiItemID;

        _stBagGrid._shCount = 0;
        _stBagGrid._stKey._ucItemType = 0;
        _stBagGrid._stKey._uiItemID = 0;
        return 0;
    }

    CStorageGrid stBagNewGrid;
    stBagNewGrid.Init(_stRoleGrid._stKey._ucItemType, _stRoleGrid._stKey._uiItemID);
    stBagNewGrid._shCount = 1;
    stBagNewGrid._stKey._usStorePos = _stBagGrid._stKey._usStorePos;
    int iRet = stPlayerOnlineData._stUserStorage.AddToBag(stBagNewGrid);
    CHECK_RETURN(iRet);

    //返回给前台信息时使用
    unsigned char ucEquipPos = _stRoleGrid._stKey._usStorePos; //穿脱位置
    short shRoleId = (short)(stReq.partner_id() & 0x7FFF);
    unsigned int uiNowEquip = 0;
    iRet = GetEquipOnRole(stPlayerDetailInfo, shRoleId, ucEquipPos, uiNowEquip);
    CHECK_RETURN(iRet);

    if (0 == uiNowEquip)
    {
        _stRoleGrid._shCount = 0;
        _stRoleGrid._stKey._ucItemType = 0;
        _stRoleGrid._stKey._uiItemID = 0;
    }
    else
    {
        _stRoleGrid.Init(ITEM_TYPE_EQUIP, uiNowEquip);
        _stRoleGrid._stKey._usStorePos = ucEquipPos;
        _stRoleGrid._shCount = 1;
    }

    _stBagGrid = stBagNewGrid;
    return 0;
}


int CCmdEquipRole::AnsClients(int iRet)
{
    pstMainCtrl->m_stEncodeBuf.Clear();

	stMsgHead.set_msgtype(CSMsgDef::EMT_ANSWER);
    stMsgHead.set_msgret(iRet);

    if (iRet != RET_OK)
    {
        pstMainCtrl->ReturnMsgHead(stMsgHead, stEnpHead);
        return Done(iRet);
    }

    pstMainCtrl->EncodePBMsg(stMsgHead, pstMainCtrl->m_stEncodeBuf);
    pstMainCtrl->EncodePBMsg(stAns, pstMainCtrl->m_stEncodeBuf);

    if (pstMainCtrl->AnswerToClient(stEnpHead, pstMainCtrl->m_stEncodeBuf, true))
    {
        CT_WARNING((""));
        return Done(RET_SYS_ERROR);
    }

    return Done(iRet);
}


CT_REGISTER_ASYNCCMD(ID_MAIN_EQUIP_MAKE_INFO, CCmdEquipMakeInfo);
int CCmdEquipMakeInfo::Do(void * pData)
{
    CT_ASSERT(pData);
    int iRet = 0;

    //解析消息
    CCmdPBDoParam* pstParam = (CCmdPBDoParam*) pData;
    pstMainCtrl = (CMainCtrl*) pstParam->m_pMain;

    if (pstParam->m_pstMsgHead->msgid() != ID_MAIN_EQUIP_MAKE_INFO ||
        pstParam->m_pstMsgHead->msgtype() != CSMsgDef::EMT_REQUEST)
    {
        CT_ERROR(("Cmd Stat Err Cmd=%d CmdID=%d Type=%d",
            ID_MAIN_EQUIP_MAKE_INFO,
            pstParam->m_pstMsgHead->msgid(),
            pstParam->m_pstMsgHead->msgtype()));
        return Done(RET_SYS_ERROR);
    }

    stMsgHead = *(pstParam->m_pstMsgHead);
    stEnpHead = *(pstParam->m_pstEnpHead);
    iRet = pstMainCtrl->DecodePBMsg(stReq, pstParam);
    if (iRet)
    {
        return AnsClients(iRet);
    }
    //消息解析结束

    _uiGID = (unsigned int)stReq.gid();

    //检查登录
    iRet = pstMainCtrl->CheckLogin(_uiGID, stEnpHead);
    if (iRet != RET_OK)
    {
        return AnsClients(iRet);
    }

    LogicDo(RET_OK);
    return iRet;
}

int CCmdEquipMakeInfo::LogicDo(int iRet)
{
    if (iRet != 0)
    {
        return AnsClients(iRet);
    }

    PREPARE_PLAYER_BASE_INFO(this, _uiGID);
    PREPARE_PLAYER_DETAIL_INFO(this, _uiGID);

    int iIndex = pstMainCtrl->m_stPlayerBaseInfoHash.HashFind(_uiGID);
    if (iIndex < 0)
    {
        CT_ERROR(("get user player base info error, uid = %u", _uiGID));
        return AnsClients(RET_SYSTEM_FAIL);
    }
    CPlayerBaseInfo& stPlayerBaseInfo = pstMainCtrl->m_stPlayerBaseInfoHash[iIndex];

    if (stPlayerBaseInfo._ucIsInited != 1)
    {
        return AnsClients(ERROR_NOT_INITED);
    }

    iIndex = pstMainCtrl->m_stPlayerDetailInfoHash.HashFind(_uiGID);
    if (iIndex < 0)
    {
        return AnsClients(RET_NO_USER);
    }
    CPlayerDetailInfo& stPlayerDetailInfo = pstMainCtrl->m_stPlayerDetailInfoHash[iIndex];

    iIndex = pstMainCtrl->m_stPlayerOnlineDataHash.HashFind(_uiGID);
    if (iIndex < 0)
    {
        CT_ERROR(("user %u not in m_stPlayerOnlineDataHash", _uiGID));
        pstMainCtrl->SetOffline(_uiGID, stEnpHead);
        return AnsClients(RET_SYSTEM_FAIL);

    }
    CPlayerOnlineData& stPlayerOnlineData = pstMainCtrl->m_stPlayerOnlineDataHash[iIndex];

    unsigned char ucStorageType =  (unsigned char)(stReq.storage_type() & 0x7F);
    unsigned int uiEquipId = 0;
    if (STORAGE_TYPE_BAG != ucStorageType)
    {
        unsigned char ucPos =  (unsigned char)(stReq.pos() & 0x7F);
        if (0 == stReq.role_id())
        {
            iRet = stPlayerDetailInfo._stPlayerEquip.GetEquip(uiEquipId, ucPos);
        }
        else
        {
           iRet = stPlayerDetailInfo._stUserPartner.GetEquip((short)stReq.role_id(), uiEquipId, ucPos);
        }

        if (iRet)
        {
            return AnsClients(iRet);
        }
    }

    iRet = GetEquipMakeInfo (stPlayerOnlineData, uiEquipId);
    if (iRet)
    {
        return AnsClients(iRet);
    }

    return AnsClients(RET_OK);
}

int CCmdEquipMakeInfo::GetEquipMakeInfo (CPlayerOnlineData& stPlayerOnlineData, unsigned int uiEquipId)
{
    unsigned char ucStorageType =  (unsigned char)(stReq.storage_type() & 0x7F);
    if ((0 == uiEquipId)
        && (STORAGE_TYPE_BAG != ucStorageType))
    {
        return ERROR_EQUIP_NOT_EXIST;
    }

    int iRet;
    unsigned short usScrollConfigID = 0;
    unsigned short usStrengthLevel = 0;

    //找到制作卷轴的配置
    if (STORAGE_TYPE_ROLE_EQUIP != ucStorageType)
    {
        CT_ERROR(("%d, %d", _uiGID, ucStorageType));
        return ERROR_EQUIP_MAKE_EQUIP;
    }

    CSingleEquip stEquip;
    iRet = pstMainCtrl->m_stEquipMgr.GetEquip(stPlayerOnlineData._stUserEquip, uiEquipId, stEquip);
    CHECK_RETURN(iRet);

    CEquipConfigData stEquipConfig;
    iRet = pstMainCtrl->m_stEquipMgr.GetConfigData(stEquip._usEquipConfigID, stEquipConfig);
    CHECK_RETURN(iRet);

    usScrollConfigID = stEquipConfig._usScrollId;
    usStrengthLevel = stEquip._usStrengthenLevel;

    CScrollConfigData stScrollConfig;
    iRet = pstMainCtrl->m_stItemMgr.GetScrollConfig(usScrollConfigID, stScrollConfig);
    CHECK_RETURN(iRet);

    int iScrollCnt = pstMainCtrl->m_stStorageMgr.GetItemCount(stPlayerOnlineData._stUserStorage, ITEM_TYPE_SCROLL, stScrollConfig._usSrollConfigID);
#if 0
    if (iScrollCnt <= 0)
    {
        return ERROR_EQUIP_MAKE_LACK_SCROLL;
    }
#endif
    //找到待制作的装备和强化等级

    MsgEquipAttr stEquipAttr;
    iRet = pstMainCtrl->m_stEquipMgr.GetEquipAttr(stScrollConfig._usOldEquipConfigID, usStrengthLevel, stEquipAttr);
    CHECK_RETURN(iRet);
    *(stAns.mutable_old_equip_attr()) = stEquipAttr;

    stAns.set_new_equip_cfg_id(stScrollConfig._usNewEquipConfigID);
    unsigned short usNewEquipStrength;
    iRet = pstMainCtrl->m_stEquipMgr.GetNewEquipStrength(usStrengthLevel, usNewEquipStrength);
    iRet = pstMainCtrl->m_stEquipMgr.GetEquipAttr(stScrollConfig._usNewEquipConfigID, usNewEquipStrength, stEquipAttr);
    CHECK_RETURN(iRet);
    *(stAns.mutable_new_equip_attr()) = stEquipAttr;

    MsgItemSynInfo * pstSynItem;
    pstSynItem = stAns.add_items();

    CInstanceId stDropInstanceId;
    pstMainCtrl->m_stInstanceMgr.GetDropInstanceID(ITEM_TYPE_SCROLL, stScrollConfig._usSrollConfigID,
        stPlayerOnlineData._stUserInstance._stInstanceData._stHasOpenedInstanceData, stDropInstanceId);
    pstSynItem->set_item_type(ITEM_TYPE_SCROLL);
    pstSynItem->set_item_cfg_id(stScrollConfig._usSrollConfigID);
    pstSynItem->set_need_item_cnt(1);
    pstSynItem->set_cur_item_cnt(iScrollCnt);
    pstSynItem->set_instance_type(stDropInstanceId._ucInstanceType);
    pstSynItem->set_instance_id(stDropInstanceId._usInstanceID);

    pstSynItem = stAns.add_items();
#if 0
    pstMainCtrl->m_stInstanceMgr.GetDropInstanceID(ITEM_TYPE_EQUIP, stScrollConfig._usOldEquipConfigID,
        stPlayerOnlineData._stUserInstance._stInstanceData._stHasOpenedInstanceData, stDropInstanceId);
    pstSynItem->set_instance_type(stDropInstanceId._ucInstanceType);
    pstSynItem->set_instance_id(stDropInstanceId._usInstanceID);
#endif
    pstSynItem->set_item_type(ITEM_TYPE_EQUIP);
    pstSynItem->set_item_cfg_id(stScrollConfig._usOldEquipConfigID);
    pstSynItem->set_need_item_cnt(1);
    pstSynItem->set_cur_item_cnt(((0 == uiEquipId) ? 0 : 1));

    for (int i = 0; i < stScrollConfig._astMaterial.Size(); i++)
    {
        pstSynItem = stAns.add_items();
        pstMainCtrl->m_stStorageMgr.GetScrollSynInfo(stPlayerOnlineData._stUserStorage, stScrollConfig._astMaterial[i], *pstSynItem);
        pstMainCtrl->m_stInstanceMgr.GetDropInstanceID(ITEM_TYPE_MATERIAL, stScrollConfig._astMaterial[i]._usMaterialId,
                             stPlayerOnlineData._stUserInstance._stInstanceData._stHasOpenedInstanceData, stDropInstanceId);
        pstSynItem->set_instance_type(stDropInstanceId._ucInstanceType);
        pstSynItem->set_instance_id(stDropInstanceId._usInstanceID);
    }

    //金钱是否足够
    int iNeedGold = 0;
    iRet = pstMainCtrl->m_stStorageMgr.GetScrollGoldCost(stPlayerOnlineData._stUserStorage, stScrollConfig._usSrollConfigID, iNeedGold);
    CHECK_RETURN(iRet);

    if (0 == uiEquipId)
    {
        iNeedGold += (int)(stScrollConfig._uiNeedGold * 1.0 / 5.0);
    }

    stAns.set_gold(iNeedGold);
    return 0;
}

int CCmdEquipMakeInfo::AnsClients(int iRet)
{
    stMsgHead.set_msgret(iRet);
    stMsgHead.set_msgtype(CSMsgDef::EMT_ANSWER);

    if (iRet != RET_OK)
    {
        pstMainCtrl->ReturnMsgHead(stMsgHead, stEnpHead);
        return Done(iRet);
    }

    stAns.set_gid(_uiGID);

    pstMainCtrl->m_stEncodeBuf.Clear();
    pstMainCtrl->EncodePBMsg(stMsgHead, pstMainCtrl->m_stEncodeBuf);
    pstMainCtrl->EncodePBMsg(stAns, pstMainCtrl->m_stEncodeBuf);

    if (pstMainCtrl->AnswerToClient(stEnpHead, pstMainCtrl->m_stEncodeBuf, true))
    {
        CT_WARNING((""));
        return Done(RET_SYS_ERROR);
    }

    return Done(iRet);
}

CT_REGISTER_ASYNCCMD(ID_MAIN_EQUIP_MAKE, CCmdEquipMake);
int CCmdEquipMake::Do(void * pData)
{
    CT_ASSERT(pData);
    int iRet = 0;

    //解析消息
    CCmdPBDoParam* pstParam = (CCmdPBDoParam*) pData;
    pstMainCtrl = (CMainCtrl*) pstParam->m_pMain;

    if (pstParam->m_pstMsgHead->msgid() != ID_MAIN_EQUIP_MAKE ||
        pstParam->m_pstMsgHead->msgtype() != CSMsgDef::EMT_REQUEST)
    {
        CT_ERROR(("Cmd Stat Err Cmd=%d CmdID=%d Type=%d",
            ID_MAIN_EQUIP_MAKE,
            pstParam->m_pstMsgHead->msgid(),
            pstParam->m_pstMsgHead->msgtype()));
        return Done(RET_SYS_ERROR);
    }

    stMsgHead = *(pstParam->m_pstMsgHead);
    stEnpHead = *(pstParam->m_pstEnpHead);
    iRet = pstMainCtrl->DecodePBMsg(stReq, pstParam);
    if (iRet)
    {
        return AnsClients(iRet);
    }
    //消息解析结束

    _uiGID = (unsigned int)stReq.gid();

    //检查登录
    iRet = pstMainCtrl->CheckLogin(_uiGID, stEnpHead);
    if (iRet != RET_OK)
    {
        return AnsClients(iRet);
    }

    LogicDo(RET_OK);
    return iRet;
}

int CCmdEquipMake::LogicDo(int iRet)
{
    if (iRet != 0)
    {
        return AnsClients(iRet);
    }

    PREPARE_PLAYER_BASE_INFO(this, stReq.gid());
    ASSERT_PLAYER_PREPARED(stReq.gid());

    PREPARE_PLAYER_DETAIL_INFO(this, stReq.gid());
    ASSERT_PLAYER_DETAIL_PREPARED(stReq.gid());

    int iIndex;
    iIndex = pstMainCtrl->m_stPlayerBaseInfoHash.HashFind(stReq.gid());
    if (iIndex < 0)
    {
        return AnsClients(RET_NO_USER);
    }
    CPlayerBaseInfo& stPlayerBaseInfo = pstMainCtrl->m_stPlayerBaseInfoHash[iIndex];

    if (stPlayerBaseInfo._ucIsInited != 1)
    {
        return AnsClients(ERROR_NOT_INITED);
    }

    iIndex = pstMainCtrl->m_stPlayerDetailInfoHash.HashFind(stReq.gid());
    if (iIndex < 0)
    {
        return AnsClients(RET_NO_USER);
    }
    CPlayerDetailInfo& stPlayerDetailInfo = pstMainCtrl->m_stPlayerDetailInfoHash[iIndex];

    iIndex = pstMainCtrl->m_stPlayerOnlineDataHash.HashFind(_uiGID);
    if (iIndex < 0)
    {
        CT_ERROR(("user %u not in m_stPlayerOnlineDataHash", _uiGID));
        pstMainCtrl->SetOffline(_uiGID, stEnpHead);
        return AnsClients(RET_SYSTEM_FAIL);
    }
    CPlayerOnlineData& stPlayerOnlineData = pstMainCtrl->m_stPlayerOnlineDataHash[iIndex];

    pstMainCtrl->m_stOssMgr.ClearKeyValueList();//oss

    //合成后的物品存放位置
    unsigned char ucStorageType =  (unsigned char)(stReq.storage_type() & 0x7F);
    unsigned char ucMakeType = (unsigned char)(stReq.make_type() & 0x7F);
    iRet = PreCheck(stPlayerBaseInfo, stPlayerDetailInfo, stPlayerOnlineData);
    if (iRet)
    {
        return AnsClients(iRet);
    }

    //消耗背包中的材料和卷轴    
    iRet = pstMainCtrl->m_stStorageMgr.MakeItem(stPlayerOnlineData._stUserStorage, _stScrollGrid, ucMakeType, true);
    if (iRet)
    {
        return AnsClients(ERROR_EQUIP_MAKE_LACK_ITEM);
    }

    //合成后生成了新的装备类型,而装备ID中编码了类型.(因此需要计算新的ID,如果是在人身上的装备先脱下旧装备,再穿上新装备).
    iRet = TakeoffEquip(stPlayerBaseInfo, stPlayerDetailInfo, stPlayerOnlineData);
    if (iRet != 0)
    {
        return AnsClients(iRet);
    }

    //制造新的装备
    iRet = pstMainCtrl->m_stEquipMgr.MakeEquip(stPlayerOnlineData._stUserEquip, _stScrollConfig, _stEquip);
    if (iRet)
    {
        return AnsClients(ERROR_EQUIP_MAKE_EQUIP);
    }

    //穿上新装备
    iRet = WareEquip(stPlayerBaseInfo, stPlayerDetailInfo, stPlayerOnlineData);
    if (iRet != 0)
    {
        return AnsClients(iRet);
    }

    if (SCROLL_USE_GOLD == ucMakeType)
    {
        iRet = pstMainCtrl->m_stItemMgr.SubGold(stPlayerBaseInfo, OSS_MONEY_MODULE_06, _iNeedGold);
        if (iRet)
        {
            return AnsClients(iRet);
        }
    }

    stAns.set_gid(_uiGID);
    stAns.set_gold(stPlayerBaseInfo._iGold);
    stAns.set_storage_type(stReq.storage_type());
    if (STORAGE_TYPE_ROLE_EQUIP == ucStorageType)
    {
        CPlayerEquipData stPlayerEquip;
        stPlayerEquip._iEquipID = _stEquip._uiEquipID;
        stPlayerEquip._iPos = stReq.pos();
        pstMainCtrl->m_stEquipMgr.GetEquipInfo(_uiGID, stPlayerEquip, *(stAns.mutable_role_grid()));
        stAns.set_role_id(stReq.role_id());
    }

    //保存数据
    pstMainCtrl->m_stEquipMgr.GetData(stPlayerOnlineData._stUserEquip, stPlayerDetailInfo._stUserEquip);
    pstMainCtrl->m_stStorageMgr.GetData(stPlayerOnlineData._stUserStorage, stPlayerDetailInfo._stUserStorage);
    CVarObjectKey stKey;
    stKey.m_chDataType = DT_PLAYER_BASE_INFO;
    stKey.m_u64ID = stPlayerBaseInfo._uiGID;
    pstMainCtrl->UpdateData(stKey, stPlayerBaseInfo, VOP_UPDATE);

    stKey.m_chDataType = DT_PLAYER_DETAIL_INFO;
    stKey.m_u64ID = stPlayerDetailInfo._uiGID;
    pstMainCtrl->UpdateData(stKey, stPlayerDetailInfo, VOP_UPDATE);

    //刷新背包/仓库数据
    pstMainCtrl->m_stNotifyMgr.Notify(stPlayerBaseInfo._uiGID, NOTIFY_USER_MONEY | NOTIFY_BAG_INFO);

    pstMainCtrl->m_stOssMgr.TriggerItem(_uiGID, OSS_ITEM_MAKE_EQUIP);//oss

    return AnsClients(RET_OK);
}

int CCmdEquipMake::PreCheck (CPlayerBaseInfo& stPlayerBaseInfo, CPlayerDetailInfo& stPlayerDetailInfo, CPlayerOnlineData& stPlayerOnlineData)
{
    //系统开放检查
    if (!pstMainCtrl->m_stCommConfigLoader.IsOpen(SYS_OPEN_COND_ID_40, stPlayerBaseInfo, stPlayerOnlineData))
    {
        return ERROR_SYS_NOT_OPEN;
    }

    unsigned char ucStorageType =  (unsigned char)(stReq.storage_type() & 0x7F);
    unsigned char ucMakeType = (unsigned char)(stReq.make_type() & 0x7F);
    unsigned short usPos = (unsigned short)(stReq.pos() & 0X7FFF);

    int iRet;
    CEquipConfigData stEquipConfig;

    if (STORAGE_TYPE_ROLE_EQUIP != ucStorageType)
    {
        CT_ERROR(("%d, %d", _uiGID, ucStorageType));
        return ERROR_EQUIP_MAKE_EQUIP;
    }

    unsigned int uiEquipId = 0;
    if(0 == stReq.role_id())
    {
        iRet = stPlayerDetailInfo._stPlayerEquip.GetEquip(uiEquipId, usPos);
    }
    else
    {
        short shResID = (short)(stReq.role_id() & 0x7F);
        iRet = stPlayerDetailInfo._stUserPartner.GetEquip(shResID, uiEquipId, usPos);
    }
    CHECK_RETURN(iRet);

    //主角或者伙伴身上当前无装备
    if (0 == uiEquipId)
    {
        return ERROR_EQUIP_NOT_EXIST;
    }

    iRet = pstMainCtrl->m_stEquipMgr.GetEquip(stPlayerOnlineData._stUserEquip, uiEquipId, _stEquip);
    CHECK_RETURN(iRet);

    iRet = pstMainCtrl->m_stEquipMgr.GetConfigData(_stEquip._usEquipConfigID, stEquipConfig);
    CHECK_RETURN(iRet);

    iRet = pstMainCtrl->m_stItemMgr.GetScrollConfig(stEquipConfig._usScrollId, _stScrollConfig);
    CHECK_RETURN(iRet);

    int iScrollCnt = pstMainCtrl->m_stStorageMgr.GetItemCount(stPlayerOnlineData._stUserStorage, ITEM_TYPE_SCROLL, _stScrollConfig._usSrollConfigID);
    if (iScrollCnt <= 0)
    {
        return ERROR_EQUIP_MAKE_LACK_SCROLL;
    }

    //在CStorageMgr::MakeItem中会检查合成的材料是否足够
    _stScrollGrid._stKey._ucItemType = ITEM_TYPE_SCROLL;
    _stScrollGrid._stKey._uiItemID = _stScrollConfig._usSrollConfigID;
    _stScrollGrid._shCount = 1;

    //检查主角的等级是否达到合成后装备的等级
    short shToLevel = stPlayerBaseInfo._shLevel;
    short shResID = (short)(stReq.role_id());
    if(0 != shResID)
    {
        int iIndex = stPlayerDetailInfo._stUserPartner.FindActData(shResID);
        if (iIndex < 0)
        {
            return ERROR_EQUIP_PARTNER_ACT;
        }

        const CPartnerActData& stPartner = stPlayerDetailInfo._stUserPartner.GetPartnerActData(iIndex);
        shToLevel = stPartner._shLevel;
    }

    iRet = pstMainCtrl->m_stEquipMgr.GetConfigData(_stScrollConfig._usNewEquipConfigID, stEquipConfig);
    CHECK_RETURN(iRet);

    if ((shToLevel < stEquipConfig._usUseLevel)
        || (shToLevel < _stScrollConfig._usUseLevel))
    {
        CT_ERROR(("%d, %d, %d, %d", _uiGID,  shToLevel, stEquipConfig._usUseLevel, _stScrollConfig._usUseLevel));
        return ERROR_EQUIP_ROLE_LEVEL;
    }
    //////////////////////////////////////////////////////////////////////////

    //金钱是否足够
    iRet = pstMainCtrl->m_stStorageMgr.GetScrollGoldCost(stPlayerOnlineData._stUserStorage, _stScrollConfig._usSrollConfigID, _iNeedGold);
    CHECK_RETURN(iRet);

    if (0 == _stEquip._uiEquipID)
    {
        _iNeedGold += (int)(_stScrollConfig._uiNeedGold * 1.0 / 5.0);
    }

    if (_iNeedGold < 0)
    {
        return ERROR_GOLD_VALID;
    }

    if ((SCROLL_USE_GOLD == ucMakeType)
         && (stPlayerBaseInfo._iGold < _iNeedGold))
    {
        return ERROR_EQUIP_LACK_GOLD;
    }
    //////////////////////////////////////////////////////////////////////////

    return 0;
}

int CCmdEquipMake::TakeoffEquip(CPlayerBaseInfo& stPlayerBaseInfo, CPlayerDetailInfo& stPlayerDetailInfo, CPlayerOnlineData& stPlayerOnlineData)
{
    int iRet = 0;
    unsigned char ucPos = (unsigned char)(stReq.pos() & 0X7F);
    short shRoleId = (short)(stReq.role_id() & 0X7FFF);

    //伙伴身上的当前装备
    unsigned int uiNowEquip = 0;
    if (shRoleId != 0)
    {
        iRet = stPlayerDetailInfo._stUserPartner.GetEquip(shRoleId, uiNowEquip, ucPos);
    }
    else
    {
        iRet = stPlayerDetailInfo._stPlayerEquip.GetEquip(uiNowEquip, ucPos);
    }

    if (0 == uiNowEquip)
    {
        return 0;
    }

    //在装备控制器中, 保存穿戴的伙伴信息
    iRet = pstMainCtrl->m_stEquipMgr.TakeOffEquip(stPlayerOnlineData._stUserEquip, uiNowEquip);
    CHECK_RETURN(iRet);

    //脱下身上已有的装备
    if (shRoleId != 0)
    {
        iRet = pstMainCtrl->m_stPartnerMgr.PartnerTakeOffEquip(shRoleId,
            stPlayerBaseInfo, stPlayerDetailInfo, stPlayerOnlineData,
            uiNowEquip, ucPos);

    }
    else
    {
        iRet = pstMainCtrl->m_stRoleMgr.RoleTakeOffEquip(stPlayerBaseInfo, stPlayerDetailInfo,
                                                     stPlayerOnlineData, uiNowEquip, ucPos);
    }

    if (iRet)
    {
        CT_ERROR (("gid: %d, partner %d, equipid: %d", stPlayerBaseInfo._uiGID, shRoleId, uiNowEquip));
        return iRet;
    }

    return 0;
}

int CCmdEquipMake::WareEquip(CPlayerBaseInfo& stPlayerBaseInfo, CPlayerDetailInfo& stPlayerDetailInfo, CPlayerOnlineData& stPlayerOnlineData)
{
    int iRet = 0;
    short shRoleId = (short)(stReq.role_id() & 0X7FFF);
    unsigned char ucPos = (unsigned char)(stReq.pos() & 0X7F);

    //在装备控制器中,  保存穿戴的伙伴信息
    iRet = pstMainCtrl->m_stEquipMgr.WearEquip(stPlayerOnlineData._stUserEquip, _stEquip._uiEquipID, shRoleId);
    CHECK_RETURN(iRet);

    //在人物身上保存装备ID
    if (shRoleId != 0)
    {
        iRet = pstMainCtrl->m_stPartnerMgr.PartnerWearEquip(shRoleId,
            stPlayerBaseInfo, stPlayerDetailInfo, stPlayerOnlineData,
            _stEquip._uiEquipID, ucPos);
        CHECK_RETURN(iRet);
    }
    else
    {
        iRet = pstMainCtrl->m_stRoleMgr.RoleWearEquip(stPlayerBaseInfo, stPlayerDetailInfo,
                                    stPlayerOnlineData, _stEquip._uiEquipID, ucPos);
        CHECK_RETURN(iRet);
    }

    return 0;
}

int CCmdEquipMake::AnsClients(int iRet)
{
    pstMainCtrl->m_stEncodeBuf.Clear();

    stMsgHead.set_msgret(iRet);
    stMsgHead.set_msgtype(CSMsgDef::EMT_ANSWER);

    if (iRet != RET_OK)
    {
        pstMainCtrl->ReturnMsgHead(stMsgHead, stEnpHead);
        return Done(iRet);
    }

    stAns.set_gid(stReq.gid());
    stAns.set_storage_type(stReq.storage_type());
    pstMainCtrl->EncodePBMsg(stMsgHead, pstMainCtrl->m_stEncodeBuf);
    pstMainCtrl->EncodePBMsg(stAns, pstMainCtrl->m_stEncodeBuf);

    if (pstMainCtrl->AnswerToClient(stEnpHead, pstMainCtrl->m_stEncodeBuf, true))
    {
        CT_WARNING((""));
        return Done(RET_SYS_ERROR);
    }

    return Done(iRet);
}

CT_REGISTER_ASYNCCMD(ID_MAIN_EQUIP_STRENGTH, CCmdEquipStrength);
int CCmdEquipStrength::Do(void * pData)
{
    CT_ASSERT(pData);
    int iRet = 0;

    //解析消息
    CCmdPBDoParam* pstParam = (CCmdPBDoParam*) pData;
    pstMainCtrl = (CMainCtrl*) pstParam->m_pMain;

    if (pstParam->m_pstMsgHead->msgid() != ID_MAIN_EQUIP_STRENGTH ||
        pstParam->m_pstMsgHead->msgtype() != CSMsgDef::EMT_REQUEST)
    {
        CT_ERROR(("Cmd Stat Err Cmd=%d CmdID=%d Type=%d",
            ID_MAIN_EQUIP_STRENGTH,
            pstParam->m_pstMsgHead->msgid(),
            pstParam->m_pstMsgHead->msgtype()));
        return Done(RET_SYS_ERROR);
    }

    stMsgHead = *(pstParam->m_pstMsgHead);
    stEnpHead = *(pstParam->m_pstEnpHead);
    iRet = pstMainCtrl->DecodePBMsg(stReq, pstParam);
    if (iRet)
    {
        return AnsClients(iRet);
    }
    //消息解析结束

    _uiGID = (unsigned int)stReq.gid();

    //检查登录
    iRet = pstMainCtrl->CheckLogin(_uiGID, stEnpHead);
    if (iRet != RET_OK)
    {
        return AnsClients(iRet);
    }

    LogicDo(RET_OK);
    return iRet;
}

int CCmdEquipStrength::LogicDo(int iRet)
{
    if (iRet != 0)
    {
        return AnsClients(iRet);
    }

    PREPARE_PLAYER_BASE_INFO(this, stReq.gid());
    ASSERT_PLAYER_PREPARED(stReq.gid());

    PREPARE_PLAYER_DETAIL_INFO(this, stReq.gid());
    ASSERT_PLAYER_DETAIL_PREPARED(stReq.gid());

    PREPARE_PLAYER_DETAIL_EX1_INFO(this, stReq.gid());
    ASSERT_PLAYER_DETAIL_EX1_INFO(stReq.gid());

    PREPARE_PLAYER_SNS_DETAIL_INFO(this, stReq.gid());

    int iIndex;
    iIndex = pstMainCtrl->m_stPlayerBaseInfoHash.HashFind(_uiGID);
    if (iIndex < 0)
    {
        return AnsClients(RET_NO_USER);
    }
    CPlayerBaseInfo& stPlayerBaseInfo = pstMainCtrl->m_stPlayerBaseInfoHash[iIndex];

    if (stPlayerBaseInfo._ucIsInited != 1)
    {
        return AnsClients(ERROR_NOT_INITED);
    }

    iIndex = pstMainCtrl->m_stPlayerDetailInfoHash.HashFind(_uiGID);
    if (iIndex < 0)
    {
        return AnsClients(RET_NO_USER);
    }
    CPlayerDetailInfo& stPlayerDetailInfo = pstMainCtrl->m_stPlayerDetailInfoHash[iIndex];

    iIndex = pstMainCtrl->m_stPlayerDetailEx1InfoHash.HashFind(_uiGID);
    if (iIndex < 0)
    {
        CT_ERROR(("get user detail ex1 info error, uid = %u", _uiGID));
        return AnsClients(RET_SYSTEM_FAIL);
    }
    CPlayerDetailInfoEx1& stPlayerDetailEx1Info = pstMainCtrl->m_stPlayerDetailEx1InfoHash[iIndex];

    iIndex = pstMainCtrl->m_stPlayerSnsDetailInfoHash.HashFind(_uiGID);
    if (iIndex < 0)
    {
        return AnsClients(RET_NO_USER);
    }
    CPlayerSnsDetailInfo& stPlayerSnsDetailInfo = pstMainCtrl->m_stPlayerSnsDetailInfoHash[iIndex];

    iIndex = pstMainCtrl->m_stPlayerOnlineDataHash.HashFind(_uiGID);
    if (iIndex < 0)
    {
        CT_ERROR(("user %u not in m_stPlayerOnlineDataHash", _uiGID));
        pstMainCtrl->SetOffline(_uiGID, stEnpHead);
        return AnsClients(RET_SYSTEM_FAIL);
    }
    CPlayerOnlineData& stPlayerOnlineData = pstMainCtrl->m_stPlayerOnlineDataHash[iIndex];

    //检查系统是否开启
    if (!pstMainCtrl->m_stCommConfigLoader.IsOpen(SYS_OPEN_COND_ID_2, stPlayerBaseInfo, stPlayerOnlineData))
    {
        return AnsClients(ERROR_SYS_NOT_OPEN);
    }

    unsigned char ucOperType = (unsigned char)(stReq.oper_type() & 0x7F);
    unsigned char ucWearPos = (unsigned char)(stReq.equip_wear_pos() & 0x7F);
    unsigned int uiRoleId = (unsigned int)(stReq.role_id() & 0x7FFFFFFF);
    unsigned int uiEquipId;

    short shToLevel = stPlayerBaseInfo._shLevel;
    if(0 == uiRoleId)
    {        
        iRet = stPlayerDetailInfo._stPlayerEquip.GetEquip(uiEquipId, ucWearPos);
    }
    else
    {
#if 0
//TASK #233::伙伴已使用的装备的强化等级上限改为以主角等级为上限
        short shResID = (short)(uiRoleId);
        iIndex = stPlayerDetailInfo._stUserPartner.FindActData(shResID);
        if (iIndex < 0)
        {
            return AnsClients(ERROR_EQUIP_PARTNER_ACT);
        }

        const CPartnerActData& stPartner = stPlayerDetailInfo._stUserPartner.GetPartnerActData(iIndex);
        shToLevel = stPartner._shLevel;
#endif
        iRet = stPlayerDetailInfo._stUserPartner.GetEquip((short)(uiRoleId), uiEquipId, ucWearPos);
    }

    if (iRet)
    {
        return AnsClients(ERROR_EQUIP_NOT_EXIST);
    }

    uint64 ui64EquipKey = pstMainCtrl->m_stEquipMgr.MakeEquipKey(_uiGID, uiEquipId);
    iIndex = stPlayerOnlineData._stUserEquip._stEquipHash.HashFind(ui64EquipKey);
    if (iIndex < 0)
    {
        return AnsClients(ERROR_EQUIP_NOT_EXIST);
    }
    CSingleEquip & stEquip = stPlayerOnlineData._stUserEquip._stEquipHash[iIndex];

    if (OPER_REQ_STRENGTH == ucOperType)
    {
        if (stEquip._usStrengthenLevel == MAX_EQUIP_STRENGTH_LEVEL)
        {
            return AnsClients(ERROR_EQUIP_STRENGTH_FULL);
        }

        if (stEquip._usStrengthenLevel >= shToLevel)
        {
            return AnsClients(ERROR_EQUIP_WRONG_STRENGTH);
        }

        int iSilver;
        pstMainCtrl->m_stEquipMgr.GetEquipStrengthPrice(stEquip._usEquipConfigID, stEquip._usStrengthenLevel, iSilver);
        if ( stPlayerBaseInfo._i64Silver < iSilver)
        {
            return AnsClients(ERROR_EQUIP_LACK_SILVER);
        }

        stEquip._usStrengthenLevel += 1;
        iRet = pstMainCtrl->m_stItemMgr.SubSilver(stPlayerBaseInfo, iSilver, 0);
        CT_RETURN(iRet);
        if (iRet)
        {
            return AnsClients(iRet);
        }

        if (0 == uiRoleId)
        {
            pstMainCtrl->m_stNotifyMgr.Notify(stPlayerBaseInfo._uiGID, NOTIFY_ROLE_ATTR);
        }
        else
        {
            pstMainCtrl->m_stNotifyMgr.Notify(stPlayerBaseInfo._uiGID, NOTIFY_PARTNER_ATTR, uiRoleId);
        }

        if (iRet)
        {
            CT_WARNING ((""));
        }

        //触发任务
        if (iRet == RET_OK)
        {
            if (stEquip._usStrengthenLevel > stPlayerSnsDetailInfo._stMyInfo._stPlayerStatic._iMaxEquipStrengthLevel)
            {
                stPlayerSnsDetailInfo._stMyInfo._stPlayerStatic._iMaxEquipStrengthLevel = stEquip._usStrengthenLevel;

                CVarObjectKey stKey;
                stKey.m_chDataType = DT_PLAYER_SNS_DETAIL_INFO;
                stKey.m_u64ID = stPlayerSnsDetailInfo._uiGID;
                pstMainCtrl->UpdateData(stKey, stPlayerSnsDetailInfo, VOP_UPDATE);
            }

            pstMainCtrl->m_stTaskMgr.TriggerDoSomeOpt(stPlayerOnlineData._stUserTask, 108000 + ucWearPos, 1); //强化装备任务
            pstMainCtrl->m_stTaskMgr.TriggerDoSomeOpt(stPlayerOnlineData._stUserTask, 113000 + stPlayerSnsDetailInfo._stMyInfo._stPlayerStatic._iMaxEquipStrengthLevel, 1); //强化到多少级
            pstMainCtrl->m_stTaskMgr.TriggerDoSomeOpt(stPlayerOnlineData._stUserTask, TASK_OPT_ID_121, 1);

            //新手目标
            pstMainCtrl->m_stNewbieTaskMgr.Trigger(stPlayerDetailEx1Info._stNewbieTaskUserData, _uiGID, NEWBIE_TASK_COND_4, 
                                                                    stEquip._usStrengthenLevel);
        }

        //保存数据
        pstMainCtrl->m_stEquipMgr.GetData(stPlayerOnlineData._stUserEquip, stPlayerDetailInfo._stUserEquip);
        pstMainCtrl->m_stStorageMgr.GetData(stPlayerOnlineData._stUserStorage, stPlayerDetailInfo._stUserStorage);

        CVarObjectKey stKey;
        stKey.m_chDataType = DT_PLAYER_BASE_INFO;
        stKey.m_u64ID = stPlayerBaseInfo._uiGID;
        pstMainCtrl->UpdateData(stKey, stPlayerBaseInfo, VOP_UPDATE);

        stKey.m_chDataType = DT_PLAYER_DETAIL_INFO;
        stKey.m_u64ID = stPlayerDetailInfo._uiGID;
        pstMainCtrl->UpdateData(stKey, stPlayerDetailInfo, VOP_UPDATE);

    }

    MsgEquipAttr stEquipAttr;
    pstMainCtrl->m_stEquipMgr.GetEquipAttr(stEquip._usEquipConfigID,
                    stEquip._usStrengthenLevel, stEquipAttr);
    *(stAns.mutable_cur_equip_attr()) = stEquipAttr;

    if (stEquip._usStrengthenLevel < MAX_EQUIP_STRENGTH_LEVEL)
    {
        pstMainCtrl->m_stEquipMgr.GetEquipAttr(stEquip._usEquipConfigID,
                        stEquip._usStrengthenLevel + 1, stEquipAttr);
        *(stAns.mutable_next_equip_attr()) = stEquipAttr;

        int iSilver = 0;
        pstMainCtrl->m_stEquipMgr.GetEquipStrengthPrice(stEquip._usEquipConfigID, stEquip._usStrengthenLevel, iSilver);
        stAns.set_strength_need_silver(iSilver);
        CTSizeString<64>  sSilver;
        sSilver.Set("%u", stPlayerBaseInfo._i64Silver);
        stAns.set_silver(sSilver());
    }

    //推送装备信息
    ::google::protobuf::RepeatedField<int64> stReqIDList;
    stReqIDList.Add(stEquip._uiEquipID);
    pstMainCtrl->m_stEquipMgr.SendEquipDetailInfoToFront(stPlayerOnlineData, stReqIDList, stMsgHead, stEnpHead);

    pstMainCtrl->m_stNotifyMgr.Notify(_uiGID, NOTIFY_USER_MONEY);
    stAns.set_role_id(uiRoleId);
    stAns.set_wear_pos(ucWearPos);
    return AnsClients(RET_OK);
}

int CCmdEquipStrength::AnsClients(int iRet)
{
    pstMainCtrl->m_stEncodeBuf.Clear();

    stMsgHead.set_msgret(iRet);
    stMsgHead.set_msgtype(CSMsgDef::EMT_ANSWER);

    if (iRet != RET_OK)
    {
        pstMainCtrl->ReturnMsgHead(stMsgHead, stEnpHead);
        return Done(iRet);
    }

    stAns.set_gid(stReq.gid());
    pstMainCtrl->EncodePBMsg(stMsgHead, pstMainCtrl->m_stEncodeBuf);
    pstMainCtrl->EncodePBMsg(stAns, pstMainCtrl->m_stEncodeBuf);

    if (pstMainCtrl->AnswerToClient(stEnpHead, pstMainCtrl->m_stEncodeBuf, true))
    {
        CT_WARNING((""));
        return Done(RET_SYS_ERROR);
    }

    return Done(iRet);
}

CT_REGISTER_ASYNCCMD(ID_MAIN_EQUIP_CRYSTAL, CCmdEquipCrystal);
int CCmdEquipCrystal::Do(void * pData)
{
    CT_ASSERT(pData);
    int iRet = 0;

    //解析消息
    CCmdPBDoParam* pstParam = (CCmdPBDoParam*) pData;
    pstMainCtrl = (CMainCtrl*) pstParam->m_pMain;

    if (pstParam->m_pstMsgHead->msgid() != ID_MAIN_EQUIP_CRYSTAL ||
        pstParam->m_pstMsgHead->msgtype() != CSMsgDef::EMT_REQUEST)
    {
        CT_ERROR(("Cmd Stat Err Cmd=%d CmdID=%d Type=%d",
            ID_MAIN_EQUIP_CRYSTAL,
            pstParam->m_pstMsgHead->msgid(),
            pstParam->m_pstMsgHead->msgtype()));
        return Done(RET_SYS_ERROR);
    }

    stMsgHead = *(pstParam->m_pstMsgHead);
    stEnpHead = *(pstParam->m_pstEnpHead);
    iRet = pstMainCtrl->DecodePBMsg(stReq, pstParam);
    if (iRet)
    {
        return AnsClients(iRet);
    }
    //消息解析结束

    _uiGID = (unsigned int)stReq.gid();

    //检查登录
    iRet = pstMainCtrl->CheckLogin(_uiGID, stEnpHead);
    if (iRet != RET_OK)
    {
        return AnsClients(iRet);
    }

    LogicDo(RET_OK);
    return iRet;
}

int CCmdEquipCrystal::LogicDo(int iRet)
{
    if (iRet != 0)
    {
        return AnsClients(iRet);
    }

    PREPARE_PLAYER_DETAIL_INFO(this, stReq.gid());
    ASSERT_PLAYER_DETAIL_PREPARED(stReq.gid());

    PREPARE_PLAYER_DETAIL_EX1_INFO(this, stReq.gid());
    ASSERT_PLAYER_DETAIL_EX1_INFO(stReq.gid());

    int iIndex;
    iIndex = pstMainCtrl->m_stPlayerBaseInfoHash.HashFind(_uiGID);
    if (iIndex < 0)
    {
        return AnsClients(RET_NO_USER);
    }
    CPlayerBaseInfo& stPlayerBaseInfo = pstMainCtrl->m_stPlayerBaseInfoHash[iIndex];

    if (stPlayerBaseInfo._ucIsInited != 1)
    {
        return AnsClients(ERROR_NOT_INITED);
    }

    iIndex = pstMainCtrl->m_stPlayerDetailInfoHash.HashFind(_uiGID);
    if (iIndex < 0)
    {
        return AnsClients(RET_NO_USER);
    }
    CPlayerDetailInfo& stPlayerDetailInfo = pstMainCtrl->m_stPlayerDetailInfoHash[iIndex];

    iIndex = pstMainCtrl->m_stPlayerDetailEx1InfoHash.HashFind(_uiGID);
    if (iIndex < 0)
    {
        CT_ERROR(("get user detail ex1 info error, uid = %u", _uiGID));
        return AnsClients(RET_SYSTEM_FAIL);
    }
    CPlayerDetailInfoEx1& stPlayerDetailEx1Info = pstMainCtrl->m_stPlayerDetailEx1InfoHash[iIndex];

    iIndex = pstMainCtrl->m_stPlayerOnlineDataHash.HashFind(_uiGID);
    if (iIndex < 0)
    {
        CT_ERROR(("user %u not in m_stPlayerOnlineDataHash", _uiGID));
        pstMainCtrl->SetOffline(_uiGID, stEnpHead);
        return AnsClients(RET_SYSTEM_FAIL);
    }
    CPlayerOnlineData& stPlayerOnlineData = pstMainCtrl->m_stPlayerOnlineDataHash[iIndex];

    //检查系统是否开启
    if (!pstMainCtrl->m_stCommConfigLoader.IsOpen(SYS_OPEN_COND_ID_10, stPlayerBaseInfo, stPlayerOnlineData))
    {
        return AnsClients(ERROR_SYS_NOT_OPEN);
    }

    unsigned char ucOperType = (unsigned char)(stReq.oper_type() & 0x7F);
    unsigned int uiEquipID;
    CStorageGrid stResult;
    unsigned int uiNotify = 0;
    char chCrystalPos = 0;
    switch (ucOperType)
    {
    case OPER_INSET_CRYSTAL:
        {
            unsigned char ucCrystalId = (unsigned char)(stReq.crystal_id() & 0x7F);
            
            iRet = GetCrystalEquipId(uiEquipID);
            if (iRet)
            {
                return AnsClients(ERROR_EQUIP_NOT_EXIST);
            }

            iRet = pstMainCtrl->m_stEquipMgr.InsetCrystal(stPlayerDetailInfo, stPlayerOnlineData, ucCrystalId, uiEquipID, chCrystalPos);
            if (iRet)
            {
                return AnsClients(iRet);
            }

            //触发任务
            pstMainCtrl->m_stTaskMgr.TriggerDoSomeOpt(stPlayerOnlineData._stUserTask, TASK_OPT_ID_123, 1);

            CCrystalConfigData stCrystalConfigData;
            pstMainCtrl->m_stItemMgr.GetCrystalConfig(ucCrystalId, stCrystalConfigData);

            //新手目标
            pstMainCtrl->m_stNewbieTaskMgr.Trigger(stPlayerDetailEx1Info._stNewbieTaskUserData, _uiGID, NEWBIE_TASK_COND_5, 
                                        stCrystalConfigData._usLevel);

            break;
        }
    case OPER_UNSET_CRYSTAL:
        {
            if (stPlayerOnlineData._stUserStorage.BagIsFull())
            {
                return AnsClients(ERROR_UNSET_CRYSTAL_BAG_FULL);
            }

            iRet = GetCrystalEquipId(uiEquipID);
            if (iRet)
            {
                return AnsClients(ERROR_EQUIP_NOT_EXIST);
            }

            unsigned char ucCrystalId = (unsigned char)(stReq.crystal_id() & 0x7F);
            iRet = pstMainCtrl->m_stEquipMgr.UnsetCrystal(stPlayerOnlineData._stUserEquip, ucCrystalId, uiEquipID, chCrystalPos);
            if (iRet)
            {
                return AnsClients(iRet);
            }

            iRet = pstMainCtrl->m_stStorageMgr.AddItem(stPlayerOnlineData._stUserStorage, ITEM_TYPE_CRYSTAL, ucCrystalId, 1);
            if (iRet)
            {
                return AnsClients(iRet);
            }

            break;
        }
    case OPER_COMB_CRYSTAL:
        {
            unsigned char ucOldCrystalId = (unsigned char)(stReq.crystal_id() & 0x7F);
            CCrystalConfigData stCombindedCrystal; //合成后的魔晶
            iRet = pstMainCtrl->m_stItemMgr.GetCombinedCrystal(ucOldCrystalId, stCombindedCrystal);
            if (iRet)
            {
                return AnsClients(iRet);
            }

            //玩家是否达到合成魔晶需要的等级
            iRet = CheckLevel(stPlayerBaseInfo._shLevel, stCombindedCrystal._usLevel);
            if (iRet)
            {
                return AnsClients(iRet);
            }

            iRet = pstMainCtrl->m_stStorageMgr.CombineCrystal(stPlayerOnlineData._stUserStorage, ucOldCrystalId, stCombindedCrystal._usCrystalConfigID);
            if (RET_OK == iRet)
            {
                pstMainCtrl->m_stActMgr.TriggerCrystalCombine(stPlayerDetailInfo._stSplendidAct, _uiGID, stCombindedCrystal._usCrystalConfigID, 1);
            }
            break;
        }
    case OPER_ONEKEY_CRYSTAL:
        {
            unsigned char ucCombLevel = (unsigned char)(stReq.comb_level() & 0x7F);

            iRet = CheckLevel(stPlayerBaseInfo._shLevel, ucCombLevel);
            if (iRet)
            {
                return AnsClients(iRet);
            }

            if (stPlayerOnlineData._stUserStorage.BagIsFull() && stPlayerOnlineData._stUserStorage.WareHouseIsFull())
            {
                return AnsClients(ERROR_STORAGE_ADD_FULL);
            }

            pstMainCtrl->m_stStorageMgr.OneKeyCrystal(stPlayerDetailInfo, stPlayerOnlineData._stUserStorage, ucCombLevel);
            break;
        }

    //魔晶随机分解成魔晶碎片
    case OPER_DECOMPOSE_CRYSTAL:
        {
            iRet = pstMainCtrl->m_stStorageMgr.DecomposeCrystal(stPlayerBaseInfo, stPlayerOnlineData, stReq.bag_pos(), stResult);
            if (RET_OK == iRet)
            {
                CVarObjectKey stKey;
                stKey.m_chDataType = DT_PLAYER_BASE_INFO;
                stKey.m_u64ID = stPlayerBaseInfo._uiGID;
                pstMainCtrl->UpdateData(stKey, stPlayerBaseInfo, VOP_UPDATE);
                uiNotify |= (NOTIFY_USER_MONEY);
            }
            break;
        }

    //魔晶碎片随机合成一级魔晶
    case OPER_COMPOSE_CRYSTAL:
        {
            iRet = pstMainCtrl->m_stStorageMgr.ComposeCrystalFrag(stPlayerOnlineData._stUserStorage, stReq.bag_pos(), stResult);
            break;
        }
    
    //提升魔晶潜能
    case OPER_ELEVATE_POTEN :
        {
            unsigned char ucOldLevel = stPlayerBaseInfo._ucCrystalPotenLevel;
            int iOldExp = stPlayerBaseInfo._iCrystalPotenExp;
            iRet = ElevatePoten(stPlayerBaseInfo, stPlayerDetailInfo, stPlayerOnlineData);
            if (iRet)
            {
                break;
            }

            if (ucOldLevel != stPlayerBaseInfo._ucCrystalPotenLevel)
            {                
                //通知主角+伙伴的属性
                pstMainCtrl->m_stNotifyMgr.Notify(stPlayerBaseInfo._uiGID, NOTIFY_PARTNER_ATTR | NOTIFY_ROLE_ATTR);

                stAns.set_poten_up_level (stPlayerBaseInfo._ucCrystalPotenLevel - ucOldLevel);
            }
            else
            {
                stAns.set_poten_up_exp (stPlayerBaseInfo._iCrystalPotenExp - iOldExp);
                uiNotify |= NOTIFY_ROLE_INFO;
            }

            //触发任务
            pstMainCtrl->m_stTaskMgr.TriggerDoSomeOpt(stPlayerOnlineData._stUserTask, TASK_OPT_ID_130, 1);
        }
        break;

    default:
        return AnsClients(ERROR_EQUIP_CRYSTAL_OPNONE);
    }

    if (iRet)
    {
        return AnsClients(iRet);
    }

    if ( (OPER_INSET_CRYSTAL == ucOperType) || (OPER_UNSET_CRYSTAL == ucOperType))
    {
        unsigned int uiRoleId = (unsigned int)(stReq.role_id() & 0x7FFFFFFF);
        if (0 == uiRoleId)
        {
            pstMainCtrl->m_stNotifyMgr.Notify(stPlayerBaseInfo._uiGID, NOTIFY_ROLE_ATTR);
        }
        else
        {
            pstMainCtrl->m_stNotifyMgr.Notify(stPlayerBaseInfo._uiGID, NOTIFY_PARTNER_ATTR, uiRoleId);
        }

        if (iRet)
        {
            CT_WARNING ((""));
        }
    }

    //保存数据
    pstMainCtrl->m_stStorageMgr.GetData(stPlayerOnlineData._stUserStorage, stPlayerDetailInfo._stUserStorage);
    if (OPER_INSET_CRYSTAL == ucOperType || OPER_UNSET_CRYSTAL == ucOperType)
    {
        stAns.set_role_id(stReq.role_id());
        stAns.set_ware_pos(stReq.ware_pos());
        stAns.set_crystal_pos(chCrystalPos);

        ::google::protobuf::RepeatedField<int64> stReqIDList;
        stReqIDList.Add(uiEquipID);

        MsgAnsItemDetailInfos stItemInfo;
        pstMainCtrl->m_stEquipMgr.GetEquipDetailInfo(stPlayerOnlineData, stReqIDList, stItemInfo);
        *stAns.mutable_equip() = stItemInfo.equip_infos(0);

        //保存数据
        pstMainCtrl->m_stEquipMgr.GetData(stPlayerOnlineData._stUserEquip, stPlayerDetailInfo._stUserEquip);
    }
    
    uiNotify |= (NOTIFY_BAG_INFO | NOTIFY_WARE_INFO);
    pstMainCtrl->m_stNotifyMgr.Notify(_uiGID, uiNotify);
    if (!stResult.IsEmpty())
    {
        pstMainCtrl->m_stStorageMgr.GetGridInfo (_uiGID,  stResult, *(stAns.mutable_result()));
    }

    CVarObjectKey stKey;
    stKey.m_chDataType = DT_PLAYER_DETAIL_INFO;
    stKey.m_u64ID = stPlayerDetailInfo._uiGID;
    pstMainCtrl->UpdateData(stKey, stPlayerDetailInfo, VOP_UPDATE);

    return AnsClients(RET_OK);
}

int CCmdEquipCrystal::AnsClients(int iRet)
{
    stMsgHead.set_msgret(iRet);
    stMsgHead.set_msgtype(CSMsgDef::EMT_ANSWER);

    if (iRet != RET_OK)
    {
        pstMainCtrl->ReturnMsgHead(stMsgHead, stEnpHead);
        return Done(iRet);
    }

    stAns.set_oper_type(stReq.oper_type());
    pstMainCtrl->m_stEncodeBuf.Clear();
    pstMainCtrl->EncodePBMsg(stMsgHead, pstMainCtrl->m_stEncodeBuf);
    pstMainCtrl->EncodePBMsg(stAns, pstMainCtrl->m_stEncodeBuf);

    if (pstMainCtrl->AnswerToClient(stEnpHead, pstMainCtrl->m_stEncodeBuf, true))
    {
        CT_WARNING((""));
        return Done(RET_SYS_ERROR);
    }

    return Done(iRet);
}

int CCmdEquipCrystal::GetCrystalEquipId(unsigned int & uiEquipID)
{
    unsigned int uiRoleId = (unsigned int)(stReq.role_id() & 0x7FFFFFFF);
    unsigned char ucWearPos = (unsigned char)(stReq.ware_pos() & 0x7F);
    int iIndex = pstMainCtrl->m_stPlayerDetailInfoHash.HashFind(_uiGID);
    if (iIndex < 0)
    {
        return RET_SYSTEM_FAIL;
    }
    CPlayerDetailInfo& stPlayerDetailInfo = pstMainCtrl->m_stPlayerDetailInfoHash[iIndex];

    int iRet;
    if(0 == uiRoleId)
    {
        iRet = stPlayerDetailInfo._stPlayerEquip.GetEquip(uiEquipID, ucWearPos);
    }
    else
    {
        short shResID = (short)(uiRoleId);
        iRet = stPlayerDetailInfo._stUserPartner.GetEquip(shResID, uiEquipID, ucWearPos);
    }

    return iRet;
}

int CCmdEquipCrystal::CheckLevel(short sPlayerLevel, unsigned char ucCombLevel)
{
#if 0  //放开这个条件的时候,注意对嵌入魔晶时引发"魔晶合成"的影响
    
    //玩家是否达到魔晶的合成等级: 60级 < 6级魔晶, 90 < 7, 110 < 8, 120 < 9, 130 < 10, 130 = 10;

    unsigned char aucPlayerLevel[]     = { 59, 89, 109, 119, 129, 150};
    unsigned char aucMaxCrystalLevel[] = { 5,  6,  7,   8,    9,  10};

    if (ucCombLevel <= 1 || ucCombLevel > MAX_CRYSTAL_LEVLE)
    {
        return ERROR_WRONG_CRYSTAL_LEVEL;
    }

    unsigned char usMaxCrystalLevel = 1;
    unsigned char ucPlayerLevel = (unsigned char)(sPlayerLevel & 0x7F);
    for (int i = 0; i < (int)(sizeof(aucPlayerLevel)) ; i++)
    {
        if (ucPlayerLevel <= aucPlayerLevel[i])
        {
            usMaxCrystalLevel = aucMaxCrystalLevel[i];
            break;
        }
    }

    if (ucCombLevel > usMaxCrystalLevel)
    {
        return ERROR_EQUIP_ROLE_LEVEL;
    }
#endif

    return 0;
}

int CCmdEquipCrystal::ElevatePoten (CPlayerBaseInfo & stBaseInfo, CPlayerDetailInfo & stDetailInfo, CPlayerOnlineData & stOnlineData)
{
    int iUpNeedExp = pstMainCtrl->m_stEquipMgr.GetPotenUpNeedExp(stBaseInfo);
    if (iUpNeedExp <= 0)
    {
        return ERROR_MAX_POTENTIAL_LEVEL;
    }

    int iToAddExp = 0;

    int iCount = pstMainCtrl->m_stStorageMgr.GetItemCount(stOnlineData._stUserStorage, ITEM_TYPE_MATERIAL, CRYSTAL_POTEN_MATERIAL_ID);
    if (iCount > 0)
    {
        int iTakeOutCount = CT_MIN(iUpNeedExp, iCount);

        int iRet = pstMainCtrl->m_stStorageMgr.TakeOutItem(stOnlineData._stUserStorage, ITEM_TYPE_MATERIAL, CRYSTAL_POTEN_MATERIAL_ID, iTakeOutCount);
        if (iRet)
        {
            CT_ERROR(("%d, %d, %d", iRet, stBaseInfo._uiGID, iCount));
            return iRet;
        }

        iToAddExp = iTakeOutCount;
    }
    else
    {
        return ERROR_LACK_POTENTIAL_MATERIAL; //add by will

        #define DEF_POTENIAL_GOLD  20   //每点潜能的符石价格        
        int iTakeGold = CT_MIN(iUpNeedExp * DEF_POTENIAL_GOLD, (stBaseInfo._iGold / DEF_POTENIAL_GOLD) * DEF_POTENIAL_GOLD);
        if (iTakeGold > 0)
        {            
            int iRet = pstMainCtrl->m_stItemMgr.SubGold(stBaseInfo, OSS_MONEY_MODULE_49, iTakeGold);
            if (RET_OK == iRet)
            {
                iToAddExp = (iTakeGold / DEF_POTENIAL_GOLD);

                CVarObjectKey stKey;
                stKey.m_chDataType = DT_PLAYER_BASE_INFO;
                stKey.m_u64ID = stBaseInfo._uiGID;
                pstMainCtrl->UpdateData(stKey, stBaseInfo, VOP_UPDATE);
                pstMainCtrl->m_stNotifyMgr.Notify(_uiGID, NOTIFY_USER_MONEY);
            }
        }
    }

    stBaseInfo._iCrystalPotenExp += iToAddExp;

    CT_TRACE(("%d, %d, %d, %d", stBaseInfo._uiGID, iUpNeedExp, iCount, iToAddExp));

    pstMainCtrl->m_stEquipMgr.UpdatePotenLevel(stBaseInfo);    
    return 0;
}

//////////////////////////////////////////////////////////////////////////
//装备洗练
CT_REGISTER_ASYNCCMD(ID_MAIN_EQUIP_REFINE, CCmdEquipRefine);
int CCmdEquipRefine::Do(void * pData)
{
    CT_ASSERT(pData);
    int iRet = 0;

    //解析消息
    CCmdPBDoParam* pstParam = (CCmdPBDoParam*) pData;
    pstMainCtrl = (CMainCtrl*) pstParam->m_pMain;

    if (pstParam->m_pstMsgHead->msgid() != ID_MAIN_EQUIP_REFINE ||
        pstParam->m_pstMsgHead->msgtype() != CSMsgDef::EMT_REQUEST)
    {
        CT_ERROR(("Cmd Stat Err Cmd=%d CmdID=%d Type=%d",
            ID_MAIN_EQUIP_REFINE,
            pstParam->m_pstMsgHead->msgid(),
            pstParam->m_pstMsgHead->msgtype()));
        return Done(RET_SYS_ERROR);
    }

    stMsgHead = *(pstParam->m_pstMsgHead);
    stEnpHead = *(pstParam->m_pstEnpHead);
    iRet = pstMainCtrl->DecodePBMsg(stReq, pstParam);
    if (iRet)
    {
        return AnsClients(iRet);
    }
    //消息解析结束

    _uiGID = (unsigned int)stReq.gid();

    //检查登录
    iRet = pstMainCtrl->CheckLogin(_uiGID, stEnpHead);
    if (iRet != RET_OK)
    {
        return AnsClients(iRet);
    }

    LogicDo(RET_OK);
    return iRet;
}

int CCmdEquipRefine::LogicDo(int iRet)
{
    if (iRet != 0)
    {
        return AnsClients(iRet);
    }

    PREPARE_PLAYER_BASE_INFO(this, _uiGID);
    ASSERT_PLAYER_PREPARED(_uiGID);

    PREPARE_PLAYER_DETAIL_INFO(this, _uiGID);

    int iIndex;
    iIndex = pstMainCtrl->m_stPlayerBaseInfoHash.HashFind(_uiGID);
    if (iIndex < 0)
    {
        return AnsClients(RET_NO_USER);
    }
    CPlayerBaseInfo& stPlayerBaseInfo = pstMainCtrl->m_stPlayerBaseInfoHash[iIndex];

    if (stPlayerBaseInfo._ucIsInited != 1)
    {
        return AnsClients(ERROR_NOT_INITED);
    }

    iIndex = pstMainCtrl->m_stPlayerDetailInfoHash.HashFind(_uiGID);
    if (iIndex < 0)
    {
        return AnsClients(RET_NO_USER);
    }
    CPlayerDetailInfo& stPlayerDetailInfo = pstMainCtrl->m_stPlayerDetailInfoHash[iIndex];

    iIndex = pstMainCtrl->m_stPlayerOnlineDataHash.HashFind(_uiGID);
    if (iIndex < 0)
    {
        CT_ERROR(("user %u not in m_stPlayerOnlineDataHash", _uiGID));
        pstMainCtrl->SetOffline(_uiGID, stEnpHead);
        return AnsClients(RET_SYSTEM_FAIL);
    }
    CPlayerOnlineData& stPlayerOnlineData = pstMainCtrl->m_stPlayerOnlineDataHash[iIndex];

    //检查系统是否开启
    if (!pstMainCtrl->m_stCommConfigLoader.IsOpen(SYS_OPEN_COND_ID_59, stPlayerBaseInfo, stPlayerOnlineData))
    {
        return AnsClients(ERROR_SYS_NOT_OPEN);
    }

    stAns.set_opt(stReq.opt());
    stAns.set_equip_id(stReq.equip_id());
    int64 i64Tmp = CTStringUtils::StringToInt64 (stReq.equip_id().c_str(), 10);
    unsigned int uiEquipId = CT_UINT64_LOW((uint64)i64Tmp);

    bool bSaveEquipData = false;

    switch (stReq.opt())
    {
    case 1: //查询当前属性
        {
            iRet = pstMainCtrl->m_stEquipMgr.RefineEquipGetInfo(stPlayerOnlineData._stUserEquip, uiEquipId, stAns);
        }
        break;
    case 2: //洗练
        {
            //获取锁定的位置
            int iLockPos = 0;
            for (int i = 0; i < stReq.lock_pos_size(); ++i)
            {
                int iPos = stReq.lock_pos(i);
                if (iPos >= MAX_EQUIP_REFINE_ATTR_PER_EQUIP
                    || iPos < 0)
                {
                    continue;
                }

                iLockPos |= (1 << iPos);
            }

            //洗练
            iRet = pstMainCtrl->m_stEquipMgr.RefineEquip(stPlayerOnlineData, stPlayerBaseInfo, uiEquipId, iLockPos);
            
            if (RET_OK == iRet)
            {
                pstMainCtrl->m_stEquipMgr.RefineEquipGetInfo(stPlayerOnlineData._stUserEquip, uiEquipId, stAns);
                bSaveEquipData = true;
            }
        }
        break;
    case 3: //激活
        {
            bool bIsWare = false;
            short shWareRoleID = 0;
            iRet = pstMainCtrl->m_stEquipMgr.RefineEquipEnvalidAttr(stPlayerOnlineData._stUserEquip, uiEquipId, 
                            stPlayerBaseInfo, bIsWare, shWareRoleID);
        
            if (RET_OK == iRet)
            {
                pstMainCtrl->m_stEquipMgr.RefineEquipGetInfo(stPlayerOnlineData._stUserEquip, uiEquipId, stAns);

                ::google::protobuf::RepeatedField<int64> stReqIDList;
                stReqIDList.Add(uiEquipId);

                MsgAnsItemDetailInfos stItemInfo;
                pstMainCtrl->m_stEquipMgr.GetEquipDetailInfo(stPlayerOnlineData, stReqIDList, stItemInfo);
                *stAns.mutable_equip() = stItemInfo.equip_infos(0);

                bSaveEquipData = true;

                if (bIsWare)
                {
                    if (0 == shWareRoleID)
                    {
                        pstMainCtrl->m_stNotifyMgr.Notify(stPlayerBaseInfo._uiGID, NOTIFY_ROLE_ATTR);
                    }
                    else
                    {   
                        pstMainCtrl->m_stNotifyMgr.Notify(stPlayerBaseInfo._uiGID, NOTIFY_PARTNER_ATTR, shWareRoleID);
                    }
                }

                //触发任务
                pstMainCtrl->m_stTaskMgr.TriggerDoSomeOpt(stPlayerOnlineData._stUserTask, TASK_OPT_ID_129, 1);
            }
        }
        break;
    case 4: //保存属性
        {
            bool bIsWare = false;
            short shWareRoleID = 0;
            iRet = pstMainCtrl->m_stEquipMgr.RefineEquipSave(stPlayerOnlineData._stUserEquip, uiEquipId, bIsWare, shWareRoleID);
        
            if (RET_OK == iRet)
            {
                pstMainCtrl->m_stEquipMgr.RefineEquipGetInfo(stPlayerOnlineData._stUserEquip, uiEquipId, stAns);

                ::google::protobuf::RepeatedField<int64> stReqIDList;
                stReqIDList.Add(uiEquipId);

                MsgAnsItemDetailInfos stItemInfo;
                pstMainCtrl->m_stEquipMgr.GetEquipDetailInfo(stPlayerOnlineData, stReqIDList, stItemInfo);
                *stAns.mutable_equip() = stItemInfo.equip_infos(0);

                bSaveEquipData = true;

                if (bIsWare)
                {
                    if (0 == shWareRoleID)
                    {
                        pstMainCtrl->m_stNotifyMgr.Notify(stPlayerBaseInfo._uiGID, NOTIFY_ROLE_ATTR);
                    }
                    else
                    {   
                        pstMainCtrl->m_stNotifyMgr.Notify(stPlayerBaseInfo._uiGID, NOTIFY_PARTNER_ATTR, shWareRoleID);
                    }
                }
            }
        }
        break;
    default:
        iRet = RET_SYS_ERROR;
    }

    if (bSaveEquipData)
    {
        pstMainCtrl->m_stEquipMgr.GetData(stPlayerOnlineData._stUserEquip, stPlayerDetailInfo._stUserEquip);
        pstMainCtrl->m_stStorageMgr.GetData(stPlayerOnlineData._stUserStorage, stPlayerDetailInfo._stUserStorage);

        CVarObjectKey stKey;
        stKey.m_chDataType = DT_PLAYER_DETAIL_INFO;
        stKey.m_u64ID = stPlayerDetailInfo._uiGID;
        pstMainCtrl->UpdateData(stKey, stPlayerDetailInfo, VOP_UPDATE);

        stKey.m_chDataType = DT_PLAYER_BASE_INFO;
        stKey.m_u64ID = stPlayerBaseInfo._uiGID;
        pstMainCtrl->UpdateData(stKey, stPlayerBaseInfo, VOP_UPDATE);
    }

    return AnsClients(iRet);
}

int CCmdEquipRefine::AnsClients(int iRet)
{
    pstMainCtrl->m_stEncodeBuf.Clear();

    stMsgHead.set_msgret(iRet);
    stMsgHead.set_msgtype(CSMsgDef::EMT_ANSWER);

    if (iRet != RET_OK)
    {
        pstMainCtrl->ReturnMsgHead(stMsgHead, stEnpHead);
        return Done(iRet);
    }

    pstMainCtrl->EncodePBMsg(stMsgHead, pstMainCtrl->m_stEncodeBuf);
    pstMainCtrl->EncodePBMsg(stAns, pstMainCtrl->m_stEncodeBuf);

    if (pstMainCtrl->AnswerToClient(stEnpHead, pstMainCtrl->m_stEncodeBuf, true))
    {
        CT_WARNING((""));
        return Done(RET_SYS_ERROR);
    }

    return Done(iRet);
}

//////////////////////////////////////////////////////////////////////////
//装备祝福
CT_REGISTER_ASYNCCMD(ID_MAIN_EQUIP_BLESS, CCmdEquipBless);
int CCmdEquipBless::Do(void * pData)
{
    CT_ASSERT(pData);
    int iRet = 0;

    //解析消息
    CCmdPBDoParam* pstParam = (CCmdPBDoParam*) pData;
    pstMainCtrl = (CMainCtrl*) pstParam->m_pMain;

    if (pstParam->m_pstMsgHead->msgid() != ID_MAIN_EQUIP_BLESS ||
        pstParam->m_pstMsgHead->msgtype() != CSMsgDef::EMT_REQUEST)
    {
        CT_ERROR(("Cmd Stat Err Cmd=%d CmdID=%d Type=%d",
            ID_MAIN_EQUIP_BLESS,
            pstParam->m_pstMsgHead->msgid(),
            pstParam->m_pstMsgHead->msgtype()));
        return Done(RET_SYS_ERROR);
    }

    stMsgHead = *(pstParam->m_pstMsgHead);
    stEnpHead = *(pstParam->m_pstEnpHead);
    iRet = pstMainCtrl->DecodePBMsg(stReq, pstParam);
    if (iRet)
    {
        return AnsClients(iRet);
    }
    //消息解析结束

    _uiGID = (unsigned int)stReq.gid();

    //检查登录
    iRet = pstMainCtrl->CheckLogin(_uiGID, stEnpHead);
    if (iRet != RET_OK)
    {
        return AnsClients(iRet);
    }

    LogicDo(RET_OK);
    return iRet;
}

int CCmdEquipBless::LogicDo(int iRet)
{
    if (iRet != 0)
    {
        return AnsClients(iRet);
    }

    PREPARE_PLAYER_BASE_INFO(this, _uiGID);
    ASSERT_PLAYER_PREPARED(_uiGID);

    PREPARE_PLAYER_DETAIL_INFO(this, _uiGID);

    int iIndex;
    iIndex = pstMainCtrl->m_stPlayerBaseInfoHash.HashFind(_uiGID);
    if (iIndex < 0)
    {
        return AnsClients(RET_NO_USER);
    }
    CPlayerBaseInfo& stPlayerBaseInfo = pstMainCtrl->m_stPlayerBaseInfoHash[iIndex];

    if (stPlayerBaseInfo._ucIsInited != 1)
    {
        return AnsClients(ERROR_NOT_INITED);
    }

    iIndex = pstMainCtrl->m_stPlayerDetailInfoHash.HashFind(_uiGID);
    if (iIndex < 0)
    {
        return AnsClients(RET_NO_USER);
    }
    CPlayerDetailInfo& stPlayerDetailInfo = pstMainCtrl->m_stPlayerDetailInfoHash[iIndex];

    iIndex = pstMainCtrl->m_stPlayerOnlineDataHash.HashFind(_uiGID);
    if (iIndex < 0)
    {
        CT_ERROR(("user %u not in m_stPlayerOnlineDataHash", _uiGID));
        pstMainCtrl->SetOffline(_uiGID, stEnpHead);
        return AnsClients(RET_SYSTEM_FAIL);
    }
    CPlayerOnlineData& stPlayerOnlineData = pstMainCtrl->m_stPlayerOnlineDataHash[iIndex];

    //检查系统是否开启
    if (!pstMainCtrl->m_stCommConfigLoader.IsOpen(SYS_OPEN_COND_ID_60, stPlayerBaseInfo, stPlayerOnlineData))
    {
        return AnsClients(ERROR_SYS_NOT_OPEN);
    }

    stAns.set_opt(stReq.opt());
    stAns.set_equip_id(stReq.equip_id());
    int64 i64Tmp = CTStringUtils::StringToInt64 (stReq.equip_id().c_str(), 10);
    unsigned int uiEquipId = CT_UINT64_LOW((uint64)i64Tmp);

    bool bSaveEquipData = false;

    switch (stReq.opt())
    {
    case 1: //查询
        {
            iRet = pstMainCtrl->m_stEquipMgr.BlessEquipGetInfo(stPlayerOnlineData._stUserEquip, uiEquipId, stPlayerDetailInfo, stAns);
        }
        break;
    case 2: //祝福
        {
            bool bIsWare = false;
            short shWareRoleID = 0;
            iRet = pstMainCtrl->m_stEquipMgr.BlessEquip(stPlayerOnlineData._stUserEquip, uiEquipId, stPlayerBaseInfo, 
                            stPlayerDetailInfo, bIsWare, shWareRoleID);
        
            if (RET_OK == iRet)
            {
                pstMainCtrl->m_stEquipMgr.BlessEquipGetInfo(stPlayerOnlineData._stUserEquip, uiEquipId, stPlayerDetailInfo, stAns);
                bSaveEquipData = true;

                ::google::protobuf::RepeatedField<int64> stReqIDList;
                stReqIDList.Add(uiEquipId);

                MsgAnsItemDetailInfos stItemInfo;
                pstMainCtrl->m_stEquipMgr.GetEquipDetailInfo(stPlayerOnlineData, stReqIDList, stItemInfo);
                *stAns.mutable_equip() = stItemInfo.equip_infos(0);

                if (bIsWare)
                {
                    if (0 == shWareRoleID)
                    {
                        pstMainCtrl->m_stNotifyMgr.Notify(stPlayerBaseInfo._uiGID, NOTIFY_ROLE_ATTR);
                    }
                    else
                    {   
                        pstMainCtrl->m_stNotifyMgr.Notify(stPlayerBaseInfo._uiGID, NOTIFY_PARTNER_ATTR, shWareRoleID);
                    }
                }

                //任务触发
                pstMainCtrl->m_stTaskMgr.TriggerDoSomeOpt(stPlayerOnlineData._stUserTask, TASK_OPT_ID_135, 1);
            }
        }
        break;
    case 3: //升级
        {
            bool bIsWare = false;
            short shWareRoleID = 0;
            iRet = pstMainCtrl->m_stEquipMgr.BlessEquipLevelUp(stPlayerOnlineData._stUserEquip, uiEquipId, 
                            stPlayerDetailInfo, bIsWare, shWareRoleID);

            if (RET_OK == iRet)
            {
                pstMainCtrl->m_stEquipMgr.BlessEquipGetInfo(stPlayerOnlineData._stUserEquip, uiEquipId, stPlayerDetailInfo, stAns);
                bSaveEquipData = true;

                ::google::protobuf::RepeatedField<int64> stReqIDList;
                stReqIDList.Add(uiEquipId);

                MsgAnsItemDetailInfos stItemInfo;
                pstMainCtrl->m_stEquipMgr.GetEquipDetailInfo(stPlayerOnlineData, stReqIDList, stItemInfo);
                *stAns.mutable_equip() = stItemInfo.equip_infos(0);

                if (bIsWare)
                {
                    if (0 == shWareRoleID)
                    {
                        pstMainCtrl->m_stNotifyMgr.Notify(stPlayerBaseInfo._uiGID, NOTIFY_ROLE_ATTR);
                    }
                    else
                    {   
                        pstMainCtrl->m_stNotifyMgr.Notify(stPlayerBaseInfo._uiGID, NOTIFY_PARTNER_ATTR, shWareRoleID);
                    }
                }
            }
        }
        break;
    default:
        iRet = RET_SYS_ERROR;
    }

    if (bSaveEquipData)
    {
        pstMainCtrl->m_stEquipMgr.GetData(stPlayerOnlineData._stUserEquip, stPlayerDetailInfo._stUserEquip);
        pstMainCtrl->m_stStorageMgr.GetData(stPlayerOnlineData._stUserStorage, stPlayerDetailInfo._stUserStorage);

        CVarObjectKey stKey;
        stKey.m_chDataType = DT_PLAYER_DETAIL_INFO;
        stKey.m_u64ID = stPlayerDetailInfo._uiGID;
        pstMainCtrl->UpdateData(stKey, stPlayerDetailInfo, VOP_UPDATE);

        stKey.m_chDataType = DT_PLAYER_BASE_INFO;
        stKey.m_u64ID = stPlayerBaseInfo._uiGID;
        pstMainCtrl->UpdateData(stKey, stPlayerBaseInfo, VOP_UPDATE);
    }

    return AnsClients(iRet);
}

int CCmdEquipBless::AnsClients(int iRet)
{
    pstMainCtrl->m_stEncodeBuf.Clear();

    stMsgHead.set_msgret(iRet);
    stMsgHead.set_msgtype(CSMsgDef::EMT_ANSWER);

    if (iRet != RET_OK)
    {
        pstMainCtrl->ReturnMsgHead(stMsgHead, stEnpHead);
        return Done(iRet);
    }

    pstMainCtrl->EncodePBMsg(stMsgHead, pstMainCtrl->m_stEncodeBuf);
    pstMainCtrl->EncodePBMsg(stAns, pstMainCtrl->m_stEncodeBuf);

    if (pstMainCtrl->AnswerToClient(stEnpHead, pstMainCtrl->m_stEncodeBuf, true))
    {
        CT_WARNING((""));
        return Done(RET_SYS_ERROR);
    }

    return Done(iRet);
}
